#include <iostream>
#include <string>
#include <vector>
#include <boost/filesystem.hpp>
#include "util.hpp"

const std::string src_path = "data/input";
const std::string output = "data/raw_html/raw.txt";//输出目标文件地址

typedef struct DocInfol{
  std::string title;     //文档标题
  std::string content;  //文档内容
  std::string url;       //该文档在官网中的url   
}DocInfol_t;

bool EnumFile(const std::string &src_path, std::vector<std::string> *files_list);
bool ParseHtml(const std::vector<std::string> &files_list, std::vector<DocInfol_t> *results); 
bool SaveHtml(const std::vector<DocInfol_t> &results, const std::string &output);


int main()
{
  std::vector<std::string> files_list;
  //第一步，递归式将每个html文件带路径保存到files_list中，便于后期读取
  if(!EnumFile(src_path, &files_list)){
    std::cerr << "enum file name error!" << std::endl;
    return 1;
  }
  //第二步，按照files_list读取每个文件内容，并进行解析（清洗）
  std::vector<DocInfol_t> results;
  if(!ParseHtml(files_list, &results)){
    std::cerr << "parse html error" << std::endl;
    return 2;
  }
  //第三步，把解析完的各文件内容写入到output，以'\3'作为分隔符
  if(!SaveHtml(results, output)){
    std::cerr << "save html error" << std::endl;
    return 3;
  }



  return 0;
}

bool EnumFile(const std::string &src_path, std::vector<std::string> *files_list)
{
  namespace fs = boost::filesystem; 
  fs::path root_path(src_path);

  if(!fs::exists(src_path)){
    std::cerr << src_path << "not exists" << std::endl;
  }
  
  //定义一个空迭代器来判断递归结束
  fs::recursive_directory_iterator end;
  for(fs::recursive_directory_iterator iter(root_path); iter != end; iter++){
    //判断文件是否为普通文件（.html为普通文件）
    if(!fs::is_regular_file(*iter)){
      continue;
    }
    //判断文件后缀是否为.html
    if(iter->path().extension() != ".html"){
      continue;
    }

    //std::cout << "debug: " << iter->path().string() << std::endl;

    files_list->push_back(iter->path().string());//将html文件地址存入files_list
  }

  return true;
}

static bool ParseTitle(const std::string &file, std::string *title)
{
  std::size_t begin = file.find("<title>");
  if(begin == std::string::npos){
    return false;
  }

  std::size_t end = file.find("</title>");
  if(end == std::string::npos){
    return false;
  }

  begin += std::string("<title>").size();

  if(begin > end){
    return false;
  }
  *title = file.substr(begin, end-begin);//左闭右开区间，（起始位置，字符个数）
  return true;
}
static bool ParseContent(const std::string &file, std::string *content)
{
  enum status{
    LABLE,
    CONTENT
  };

  enum status s = LABLE;
  for(char c : file)
  {
    switch(s){
      case LABLE:
        if(c == '>') s = CONTENT;
        break;
      case CONTENT:
        if(c == '<') s = LABLE;
        else{
          if(c == '\n') c = ' '; //去除文件内容中的换行符
          content->push_back(c);
        }
    }
  }


  return true;
}
static bool ParseUrl(const std::string file_path, std::string *url)
{
  std::string url_head = "https://www.boost.org/doc/libs/1_78_0/doc/html";
  std::string url_tail = file_path.substr(src_path.size());
  
  *url = url_head + url_tail;
  return true;
}

bool ParseHtml(const std::vector<std::string> &files_list, std::vector<DocInfol_t> *results)
{
  //循环遍历file_list，解析数据并格式存入results
  for(const std::string &file : files_list)
  {
    //1.fileread
    std::string result;    //一次读一个文件放入result中
    if(!ns_util::FileUtil::ReadFile(file, &result))
    {
      continue; 
    }

    DocInfol_t doc; 
    //2.title
    if(!ParseTitle(result, &doc.title))
    {
      continue;
    }

    //3.content
    if(!ParseContent(result, &doc.content))
    {
      continue;
    }


    //4.url
    if(!ParseUrl(file, &doc.url))
    {
      continue;
    }
    
    //done
    results->push_back(std::move(doc));
  }


  return true;
}
bool SaveHtml(const std::vector<DocInfol_t> &results, const std::string &output)
{
#define SEP '\3'
  std::ofstream out(output, std::ios::out | std::ios::binary);
  if(!out.is_open()){
    std::cerr << "open " << output << " failed!" << std::endl;
    return false;
  }

  for(auto &item : results)
  {
    std::string out_string;
    out_string = item.title;
    out_string += SEP;
    out_string += item.content;
    out_string += SEP;    
    out_string += item.url;
    out_string += '\n';
  
    out.write(out_string.c_str(), out_string.size());
  }

  out.close();
  return true;
}














































